package com.gticket.orderservice.config;

import com.gticket.orderservice.filter.MyFormAuthenticationFilter;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.crazycake.shiro.RedisCacheManager;
import org.crazycake.shiro.RedisManager;
import org.crazycake.shiro.RedisSessionDAO;
import org.crazycake.shiro.exception.SerializationException;
import org.crazycake.shiro.serializer.RedisSerializer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer;

import javax.servlet.Filter;
import java.util.LinkedHashMap;
import java.util.Map;


@Configuration
public class ShiroConfig {

    @Value("${spring.redis.host}")
    private String redisHost;

    @Value("${spring.redis.database}")
    private int redisDatabase;

    @Value("${spring.redis.password}")
    private String redisPassword;

    @Value("${spring.cache.redis.time-to-live}")
    private int expire;

    @Value("${spring.redis.timeout}")
    private int redisTimeout;

    @Autowired

    /**
     * ShiroFilterFactoryBean 处理拦截资源文件问题。
     */
    @Bean
    public ShiroFilterFactoryBean shirFilter(SecurityManager securityManager){
        // 创建 ShiroFilterFactoryBean
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();

        /* ************* 注册自定义授权过滤器 开始******************/

        // 1、创建过滤器Map，用来装自定义过滤器
        LinkedHashMap<String, Filter> map = new LinkedHashMap<>();

        // 2、将自定义过滤器放入map中，如果实现了自定义授权过滤器，那就必须在这里注册，否则Shiro不会使用自定义的授权过滤器
        map.put("authc", new MyFormAuthenticationFilter());
        // 3、将过滤器Ma绑定到shiroFilterFactoryBean上
        shiroFilterFactoryBean.setFilters(map);


        //设置安全管理器
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        //shiroFilterFactoryBean.setUnauthorizedUrl("/login");

        //设置过滤器链
        Map<String, String> filterMap = new LinkedHashMap<>();

//      //服务器请求
        filterMap.put("/getCode", "anon");
        filterMap.put("/loginCheck","anon");
        filterMap.put("/registerCheck","anon");
        filterMap.put("/**", "authc");
//        filterMap.put("/commentPage","anon");
//        filterMap.put("/about","anon");
//        filterMap.put("/contact","anon");
//        filterMap.put("/dinning","anon");
//        filterMap.put("/gallery","anon");
//        filterMap.put("/news","anon");
//        filterMap.put("/rooms","anon");
//        filterMap.put("/showRoom","anon");
//        filterMap.put("/findLogin","anon");
//
//        filterMap.put("/dinning","anon");
//

//        //静态资源
//        filterMap.put("/assets/**", "anon");
//        filterMap.put("/bootstrapt/**", "anon");
//        filterMap.put("/css/**", "anon");
//        filterMap.put("/data/**", "anon");
//        filterMap.put("/font-awesome/**", "anon");
//        filterMap.put("/fonts/**", "anon");
//        filterMap.put("/icons-reference/**", "anon");
//        filterMap.put("/images/**", "anon");
//        filterMap.put("/jquery/**", "anon");
//        filterMap.put("/js/**", "anon");
//        filterMap.put("/js1/**", "anon");
//        filterMap.put("/libraries/**", "anon");
//        filterMap.put("/vendor/**", "anon");
//        filterMap.put("/registerPage","anon");
//        filterMap.put("/registerCheck","anon");
//
//        filterMap.put("/logout", "logout");
////      filterMap.put("/**", "anon");
//        filterMap.put("/**", "authc");
        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterMap);
        return shiroFilterFactoryBean;
    }

    @Bean
    public SecurityManager securityManager(){
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        //设置realm.
        //securityManager.setRealm(myShiroRealm());
        // 自定义缓存实现 使用redis
        securityManager.setCacheManager(cacheManager());
        // 自定义session管理 使用redis
        securityManager.setSessionManager(sessionManager());
        return securityManager;
    }

    /**
     * 身份认证realm;
     * (账号密码校验；权限等)
     * @return
     */
    /*@Bean
    public UserRealm myShiroRealm(){
        UserRealm myShiroRealm = new UserRealm();
        myShiroRealm.setCredentialsMatcher(hashedCredentialsMatcher());
        return myShiroRealm;
    }*/

    /**
     * cacheManager 缓存 redis实现
     * 使用的是shiro-redis开源插件
     */
    public RedisCacheManager cacheManager() {
        RedisCacheManager redisCacheManager = new RedisCacheManager();
        redisCacheManager.setKeySerializer(new RedisSerializer() {
            @Override
            public byte[] serialize(Object o) throws SerializationException {
                return new byte[0];
            }

            @Override
            public Object deserialize(byte[] bytes) throws SerializationException {
                return new JdkSerializationRedisSerializer();
            }
        });
        redisCacheManager.setValueSerializer(new RedisSerializer() {
            @Override
            public byte[] serialize(Object o) throws SerializationException {
                return new byte[0];
            }

            @Override
            public Object deserialize(byte[] bytes) throws SerializationException {
                return new JdkSerializationRedisSerializer();
            }
        });
        redisCacheManager.setRedisManager(redisManager());
        redisCacheManager.setExpire(expire);//缓存过期时间：秒
        return redisCacheManager;
    }

    /**
     * 配置shiro redisManager
     * 使用的是shiro-redis开源插件
     */
    public RedisManager redisManager() {
        RedisManager redisManager = new RedisManager();
        redisManager.setDatabase(redisDatabase);
        redisManager.setHost("101.132.131.239:6379");
        redisManager.setTimeout(redisTimeout);//连接redis超时
        redisManager.setPassword(redisPassword);
        return redisManager;
    }

    /**
     * Session Manager
     * 使用的是shiro-redis开源插件
     */
    @Bean
    public DefaultWebSessionManager sessionManager() {
        DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
        sessionManager.setSessionDAO(redisSessionDAO());
        return sessionManager;
    }

    /**
     * RedisSessionDAO shiro sessionDao层的实现 通过redis
     * 使用的是shiro-redis开源插件
     */
    @Bean
    public RedisSessionDAO redisSessionDAO() {
        RedisSessionDAO redisSessionDAO = new RedisSessionDAO();
        redisSessionDAO.setExpire(expire);//session会话过期时间，默认就是1800秒
        redisSessionDAO.setRedisManager(redisManager());
        return redisSessionDAO;
    }

    /**
     * 凭证匹配器
     */
    @Bean
    public HashedCredentialsMatcher hashedCredentialsMatcher(){
        HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
        hashedCredentialsMatcher.setHashAlgorithmName("md5");//散列算法:这里使用MD5算法;
        hashedCredentialsMatcher.setHashIterations(1024);//散列的次数，比如散列两次，相当于 md5(md5(""));
        return hashedCredentialsMatcher;
    }

    /**
     * 开启shiro aop注解支持.
     * 使用代理方式;所以需要开启代码支持;
     * @param securityManager
     */
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager){
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
        return authorizationAttributeSourceAdvisor;
    }
}
